//使用参见《NC Cloud最终用户许可协议》，协议内容详见安装目录
package nc.impl.hrpbm.budgetreply.budgetreply;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import nc.hrpbm.control.pub.utils.BmControlPubUtils;
import nc.impl.pubapp.pattern.data.bill.BillQuery;
import nc.itf.hrpbm.budgetctrl.service.IBmBudgetControlService;
import nc.vo.hrpbm.budgetmake.AggBudgetMakeVO;
import nc.vo.hrpbm.budgetmake.AssetAllocationVO;
import nc.vo.hrpbm.budgetmake.BudgetMakeDetailVO;
import nc.vo.hrpbm.budgetmake.BudgetMakeVO;
import nc.vo.hrpbm.budgetmake.GovpurchVO;
import nc.vo.hrpbm.hrpbmpubenum.TaskProcessEnum;
import nc.vo.hrppl.pjapplication.AggPjapplVO;
import nc.vo.pub.ISuperVO;
import nc.vo.pub.lang.UFDouble;
import nc.vo.pubapp.pattern.model.entity.bill.AbstractBill;
import nccloud.hrpbm.budget.util.ValidateAssetMoneyByProject;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import nc.bs.dao.BaseDAO;
import nc.bs.framework.common.InvocationInfoProxy;
import nc.bs.framework.common.NCLocator;
import nc.bs.hrpbm.budgetmake.util.CheckAboutHrppl;
import nc.bs.hrpbm.statemanage.TaskStateManager;
import nc.bs.hrpbm.statemanage.TaskStateProcessAction;
import nc.hrpbm.impl.control.service.BmBudgetControlServiceImpl;
import nc.bs.util.DefdocUtils;
import nc.codeplatform.framework.service.ServiceSupport;
import nc.impl.pubapp.pattern.data.vo.VOQuery;
import nc.itf.hrpbm.budgetadjust.budgetadjust.IBudgetAdjustVOService;
import nc.itf.hrpbm.budgetindicator.budgetindicatorvo.IBudgetIndicatorVOService;
import nc.itf.hrpbm.budgetmake.budgetmake.IBudgetMakeVOService;
import nc.itf.hrpbm.budgetreply.budgetreply.IBudgetReplyVOService;
import nc.itf.hrpbm.budgettype.budgettype.IBudgettypeService;
import nc.itf.hrpbm.hrpbmbudgetno.budgetno.IBudgetNoVOService;
import nc.jdbc.framework.generator.IdGenerator;
import nc.jdbc.framework.generator.SequenceGenerator;
import nc.jdbc.framework.processor.ColumnProcessor;
import nc.pub.billcode.vo.BillCodeContext;
//import nc.ui.pubapp.uif2app.actions.pflow.ApproveStatus;
import nc.vo.arap.uforeport.SqlBuffer;
import nc.vo.bc.pub.util.VOEntityUtil;
import nc.vo.hrpbm.budgetadjust.AggBudgetAdjustVO;
import nc.vo.hrpbm.budgetdept.BudgetDeptVO;
import nc.vo.hrpbm.budgetindicator.AggBudgetIndicatorVO;
import nc.vo.hrpbm.budgetindicator.BudgetIndicatorBVO;
import nc.vo.hrpbm.budgetmake.AggBudgetMakeVO;
import nc.vo.hrpbm.budgetmake.AssetAllocationVO;
import nc.vo.hrpbm.budgetmake.BudgetMakeDetailVO;
import nc.vo.hrpbm.budgetmake.GovpurchVO;
import nc.vo.hrpbm.budgetmake.SpBudgetMakeDetailVO;
import nc.vo.hrpbm.budgetreply.AggBudgetReplyVO;
import nc.vo.hrpbm.budgetreply.AssetAllocationReplyVO;
import nc.vo.hrpbm.budgetreply.BudgetReplyDetailVO;
import nc.vo.hrpbm.budgetreply.BudgetReplyVO;
import nc.vo.hrpbm.budgetreply.GovpurchReplyVO;
import nc.vo.hrpbm.budgetreply.SpBudgetReplyDetailVO;
import nc.vo.hrpbm.budgettype.Budgettype;
import nc.vo.hrpbm.hrpbmbuggetno.BudgetNoVO;
import nc.vo.hrpbm.hrpbmpubenum.TaskStageEnum;
import nc.vo.hrpbm.hrpbmpubenum.TaskStateEnum;
import nc.vo.iufo.approve.ApproveStateEnum;
import nc.vo.pub.BusinessException;
import nc.vo.pub.SuperVO;
import nc.vo.pub.VOStatus;
import nc.vo.pub.billtype.BilltypeVO;
import nc.vo.pub.lang.UFDateTime;
import nc.vo.pub.pf.BillStatusEnum;
import nc.vo.pubapp.billtype.BillTypeQueryTools;
import nccloud.hrpbm.budget.util.GenerateBudgetNo;
import nccloud.hrpbm.budget.util.GetIdCode;
import nccloud.hrpbm.budget.util.SetChildColumnValue;
import nccloud.hrpbm.budget.util.ValidateAssetAllocation;
import nccloud.hrpbm.budget.util.ValidateBudgetDetail;
import nccloud.hrpbm.budget.util.ValidateChildLength;
import nccloud.hrpbm.budget.util.ValidateOtherTwoChildLength;
import nccloud.impl.hrpbm.pub.common.HrpbmServiceSupport;

public class BudgetReplyVOServiceImpl extends ServiceSupport implements IBudgetReplyVOService {
	TaskStateManager taskStateManager = new TaskStateManager();
	private BaseDAO baseDAO = null;

	@Override
	public AggBudgetReplyVO[] listAggBudgetReplyVOByPk(String... pks) throws BusinessException {
		return listAggBudgetReplyVOByPk(false, pks);
	}

	@Override
	public AggBudgetReplyVO[] listAggBudgetReplyVOByPk(boolean blazyLoad, String... pks) throws BusinessException {
		return dao.listByPksWithOrder(AggBudgetReplyVO.class, pks, blazyLoad);
	}

	@Override
	public AggBudgetReplyVO findAggBudgetReplyVOByPk(String pk) throws BusinessException {
		return dao.findByPk(AggBudgetReplyVO.class, pk, false);
	}

	@Override
	public AggBudgetReplyVO[] listAggBudgetReplyVOByCondition(String condition) throws BusinessException {
		return listAggBudgetReplyVOByCondition(condition, new String[]{"pk_budgetreply"});
	}

	@Override
	public AggBudgetReplyVO[] listAggBudgetReplyVOByCondition(String condition, String[] orderPath)
			throws BusinessException {
		return dao.listByCondition(AggBudgetReplyVO.class, condition, false, false, orderPath);
	}

	@Override
	public BudgetReplyVO[] listBudgetReplyVOByPk(String... pks) throws BusinessException {
		return dao.listByPk(BudgetReplyVO.class, pks, true);
	}

	@Override
	public BudgetReplyVO findBudgetReplyVOByPk(String pk) throws BusinessException {
		return dao.findByPk(BudgetReplyVO.class, pk, true);
	}

	@Override
	public BudgetReplyVO[] listBudgetReplyVOByCondition(String condition) throws BusinessException {
		return listBudgetReplyVOByCondition(condition, new String[]{"pk_budgetreply"});
	}

	@Override
	public BudgetReplyVO[] listBudgetReplyVOByCondition(String condition, String[] orderPath) throws BusinessException {
		return dao.listByCondition(BudgetReplyVO.class, condition, false, false, orderPath);
	}

	@Override
	public String[] listBudgetReplyVOPkByCond(String condition) throws BusinessException {
		return listBudgetReplyVOPkByCond(condition, new String[]{"pk_budgetreply"});
	}

	@Override
	public String[] listBudgetReplyVOPkByCond(String condition, String[] orderPath) throws BusinessException {
		if (StringUtils.isEmpty(condition)) {
			condition = " 1 = 1 ";
		}
		BudgetReplyVO[] vos = dao.listByCondition(BudgetReplyVO.class, condition, false, false, orderPath);
		if (ArrayUtils.isEmpty(vos)) {
			return null;
		}
		return Arrays.stream(vos).map(vo -> vo.getPrimaryKey()).toArray(String[]::new);
	}

	@Override
	public void initDefaultData(BudgetReplyVO vo) {
		if (vo.getAttributeValue("pk_group") == null) {
			vo.setAttributeValue("pk_group", InvocationInfoProxy.getInstance().getGroupId());
		}
		if (vo.getAttributeValue("billmaker") == null) {
			vo.setAttributeValue("billmaker", InvocationInfoProxy.getInstance().getUserId());
		}
		if (vo.getAttributeValue("billmaketime") == null) {
			vo.setAttributeValue("billmaketime", new UFDateTime(InvocationInfoProxy.getInstance().getBizDateTime()));
		}
		if (vo.getAttributeValue("dbilldate") == null) {
			vo.setAttributeValue("dbilldate", new UFDateTime(InvocationInfoProxy.getInstance().getBizDateTime()));
		}
		if (vo.getAttributeValue("billtype") == null) {
			vo.setAttributeValue("billtype", "BM25");
		}
		if (vo.getAttributeValue("approvestatus") == null) {
//			vo.setAttributeValue("approvestatus", ApproveStatus.FREE);
			// modify by wy at 适配930 2024年10月28日
			vo.setAttributeValue("approvestatus", BillStatusEnum.FREE.toIntValue());
		}
	}

	@Override
	public AggBudgetReplyVO preAddAggBudgetReplyVO(AggBudgetReplyVO vo, Map<String, Object> userJson)
			throws BusinessException {

		getMainVO(vo).setStatus(VOStatus.NEW);
		initDefaultData((BudgetReplyVO) getMainVO(vo));

		// 下面这段要判断是否是树表界面插件
		Map<String, String> data = userJson != null && userJson.get("data") != null
				? (Map<String, String>) userJson.get("data")
				: null;
		if (data != null && data.size() > 0) {
			String parentKey = data.get("parentKey");
			String parentPk = data.get("parentPk");
			getMainVO(vo).setAttributeValue(parentKey, parentPk);
		}

		// 编码规则生成vo的编码
		BillCodeContext billCodeContext = getBillCodeContext("hrpbmbudgetreply");
		if (billCodeContext == null) {
			throw new BusinessException("当前编码规则不存在，请到【编码规则定义-全局】节点检查是否存在" + "hrpbmbudgetreply");
		}
		if (billCodeContext.isPrecode()) {
			String pk_group = InvocationInfoProxy.getInstance().getGroupId();
			String code = getBillcodeManage().getPreBillCode_RequiresNew("hrpbmbudgetreply", pk_group, pk_group);
			getMainVO(vo).setAttributeValue("billno", code);
		}

		return vo;
	}

	@Override
	public AggBudgetReplyVO preAddAggBudgetReplyVO(Map<String, Object> userJson) throws BusinessException {
		AggBudgetReplyVO result = null;

		BudgetReplyVO mainvo = new BudgetReplyVO();
		// 设置默认值
		initDefaultData(mainvo);
		AggBudgetReplyVO aggvo = new AggBudgetReplyVO();
		aggvo.setParent(mainvo);
		result = aggvo;
		return preAddAggBudgetReplyVO(result, userJson);
	}

	@Override
	public AggBudgetReplyVO preEditAggBudgetReplyVO(String pk) throws BusinessException {
		return dao.findByPk(AggBudgetReplyVO.class, pk, false);
	}

	@Override
	public AggBudgetReplyVO[] saveAggBudgetReplyVO(AggBudgetReplyVO vo) throws BusinessException {

		String pk = getVOPrimaryKey(vo);
		if (vo.getParentVO().getIsummary() != null) {
			if (!vo.getParentVO().getIsummary().booleanValue()) {
				setDefaultVal(vo);
			} else {
				setDefaultValDept(vo);
			}
		} else {
			setDefaultVal(vo);
		}
		//政府采购预算合计金额，资产配置预算合计金额，批复合计金额在保存后计算更新
		calculateMoneyTotal(vo);
		//新增资产中项目合计“金额”要小于等于政采中对应项目的合计“金额”。否则给出提示：**项目，新增资产预算不能大于政府采购预算，请修改，不允许保存。导入也同步验证。
		ValidateAssetMoneyByProject.validate(new AbstractBill[]{vo}, GovpurchReplyVO.class, AssetAllocationReplyVO.class);

		// 其他默认值处理
		GenerateBudgetNo generateBudgetNo = new GenerateBudgetNo();
		generateBudgetNo.generateBudgetNo(vo);

		// 计算子表vhashcode
		GetIdCode.getIdCode(vo.getAllChildrenVO());

		StringBuffer errmsg = new StringBuffer();

		if (!vo.getParentVO().getTranstype().contains("BD") && (vo.getParentVO().getTranstype().contains("YS02")
				|| vo.getParentVO().getTranstype().contains("YS04") || vo.getParentVO().getTranstype().contains("YS03"))
				&& (Objects.nonNull(vo.getChildren(GovpurchReplyVO.class)) || Objects.nonNull(vo.getChildren(AssetAllocationReplyVO.class)))) {
			// 验证政府采购和资产分配页签是否必输
			ValidateOtherTwoChildLength.validateChildLength(vo, BudgetReplyDetailVO.class, GovpurchReplyVO.class, AssetAllocationReplyVO.class, errmsg);
			// 校验资产配置页签必输项
			ValidateAssetAllocation.check((SuperVO[]) vo.getChildren(AssetAllocationReplyVO.class), errmsg);
			if (errmsg.length() > 0) {
				throw new BusinessException(errmsg.toString());
			}
		}

		// 表体引用了项目库项目并开启相关参数则进行校验
		CheckAboutHrppl.check_budgetReplay(vo);

		if (StringUtils.isEmpty(pk)) {
			AggBudgetReplyVO[] newvos = dao.insert(vo);
			// 唯一性校验，年度+编制科室+表体行按编制预算维度唯一校验（支出预算+资本预算两种类型一起校验）。
			if (vo.getParentVO().getIsummary() != null) {
				if (!vo.getParentVO().getIsummary().booleanValue()) {// 合并批复单不做唯一性校验
					ValidateBudgetDetail validateBudgetDetail = new ValidateBudgetDetail();
					String tableName = "hrpbm_budgetreplydetail";
					validateBudgetDetail.validateBudgetDetail(vo, tableName, "pk_budgetreplydetail");
				}
			} else {
				ValidateBudgetDetail validateBudgetDetail = new ValidateBudgetDetail();
				String tableName = "hrpbm_budgetreplydetail";
				validateBudgetDetail.validateBudgetDetail(vo, tableName, "pk_budgetreplydetail");
			}
			// 保存时校验在编制单是否已存在维度
			for (AggBudgetReplyVO newvo : newvos) {
				if (newvo.getParentVO().getIsummary() == null) {
					writeBackByReply(newvo);
				} else {
					if (!newvo.getParentVO().getIsummary().booleanValue()) {
						writeBackByReply(newvo);
					}
				}
			}

			return newvos; // 插入
		} else {
			//记录修改前的VO，用于推送业务控制平台
			AggBudgetReplyVO oriReplyVo = this.findAggBudgetReplyVOByPk(vo.getPrimaryKey());
			// 保存前处理编制状态
			vo = (AggBudgetReplyVO) taskStateManager.taskStateProcess(vo, TaskStateProcessAction.UPD, false, true);
			AggBudgetReplyVO[] newvos = dao.update(vo);
			newvos = this.listAggBudgetReplyVOByPk(vo.getPrimaryKey());
			// 唯一性校验，年度+编制科室+表体行按编制预算维度唯一校验（支出预算+资本预算两种类型一起校验）。
			if (vo.getParentVO().getIsummary() != null) {
				if (!vo.getParentVO().getIsummary().booleanValue()) {// 合并批复单不做唯一性校验
					ValidateBudgetDetail validateBudgetDetail = new ValidateBudgetDetail();
					String tableName = "hrpbm_budgetreplydetail";
					validateBudgetDetail.validateBudgetDetail(vo, tableName, "pk_budgetreplydetail");
				}
			} else {
				ValidateBudgetDetail validateBudgetDetail = new ValidateBudgetDetail();
				String tableName = "hrpbm_budgetreplydetail";
				validateBudgetDetail.validateBudgetDetail(vo, tableName, "pk_budgetreplydetail");
			}
			// 保存时校验在编制单是否已存在维度
			for (AggBudgetReplyVO newvo : newvos) {
				if (!newvo.getParentVO().getIsummary().booleanValue()) {
					writeBackByReply(newvo);
				}
			}
			//ADD BY WW 2024-05-14
			this.pushTempBudgetToCtrlForUpdateSave(vo, oriReplyVo);
			return newvos; // 更新
		}

	}

	/**
	 * 政府采购预算合计金额，资产配置预算合计金额，批复合计金额在保存后计算更新
	 *
	 * @param vo
	 */
	private void calculateMoneyTotal(AggBudgetReplyVO vo) {
		boolean flag = vo.getParentVO().getTaskstage() == TaskStageEnum.FirstDown.toIntValue()
				|| vo.getParentVO().getTaskstage() == TaskStageEnum.FirstDown.toIntValue();
		vo.getParentVO().setReplytotal(calculateDetailTotal(vo.getChildren(BudgetReplyDetailVO.class), flag));
		vo.getParentVO().setGovtotal(calculateTotal(vo.getChildren(GovpurchReplyVO.class)));
		vo.getParentVO().setAssettotal(calculateTotal(vo.getChildren(AssetAllocationReplyVO.class)));
	}

	private <T extends ISuperVO> UFDouble calculateDetailTotal(T[] details, boolean isFirstDown) {
		if (details == null || details.length < 1) {
			return UFDouble.ZERO_DBL;
		}
		return Arrays.stream(details)
				.filter(Objects::nonNull)
				.map(detail -> (UFDouble) detail.getAttributeValue(isFirstDown ? "amount_firstdown" : "amount_seconddown"))
				.map(amount -> amount != null ? amount : UFDouble.ZERO_DBL)  // 替换 null 为 0
				.reduce(UFDouble.ZERO_DBL, UFDouble::add);
	}

	private <T extends ISuperVO> UFDouble calculateTotal(T[] details) {
		if (details == null || details.length < 1) {
			return UFDouble.ZERO_DBL;
		}
		return Arrays.stream(details)
				.filter(Objects::nonNull)
				.map(detail -> (UFDouble) detail.getAttributeValue("money"))
				.reduce(UFDouble.ZERO_DBL, UFDouble::add);
	}


	public void writeBackByReply(AggBudgetReplyVO billVo) throws BusinessException {
		BudgetReplyDetailVO[] replyDetailVos = (BudgetReplyDetailVO[]) billVo.getChildren(BudgetReplyDetailVO.class);
		SpBudgetReplyDetailVO[] spreplyDetailVos = (SpBudgetReplyDetailVO[]) billVo.getChildren(SpBudgetReplyDetailVO.class);

		/*
		 * 取对应编制单据主键 如果存在二上编制单据则取二上编制单据主键，如果没有，则取一上编制单据主键
		 */
		String pk_budgetmake = StringUtils.isNotEmpty(billVo.getParentVO().getPk_secondupbill())
				? billVo.getParentVO().getPk_secondupbill()
				: billVo.getParentVO().getPk_firstupbill();

		AggBudgetMakeVO makeVo = this.findAggBudgetMakeVOByPk(pk_budgetmake);
		BudgetMakeDetailVO[] makeDetailVos = (BudgetMakeDetailVO[]) makeVo.getChildren(BudgetMakeDetailVO.class);

		Map<String, BudgetMakeDetailVO> makeDetailMap = new HashMap<String, BudgetMakeDetailVO>();

		for (BudgetMakeDetailVO vo : makeDetailVos) {
			makeDetailMap.put(vo.getIdcode(), vo);
		}

		// 回写数据至编制单
		BudgetMakeDetailVO tempMakeDetailVo = null;

		List<BudgetMakeDetailVO> tempMakeDetailVoList = new ArrayList<BudgetMakeDetailVO>();

		for (BudgetReplyDetailVO vo : replyDetailVos) {

			tempMakeDetailVo = makeDetailMap.get(vo.getIdcode());
			if (tempMakeDetailVo != null) { // 对应编制明细主键不为空
				tempMakeDetailVo.setStatus(VOStatus.UPDATED);
				tempMakeDetailVoList.add(tempMakeDetailVo);
			} else {
				IdGenerator idGenerator = new SequenceGenerator();
				String pkFirstDetail = idGenerator.generate();
				tempMakeDetailVo = new BudgetMakeDetailVO();
				tempMakeDetailVo.setPk_budgetmakedetail(pkFirstDetail);
				tempMakeDetailVo.setStatus(VOStatus.NEW);
				VOEntityUtil.copyVOByVO(tempMakeDetailVo, BudgetReplyDetailVO.COPY_KEYS, vo,
						BudgetReplyDetailVO.COPY_KEYS);
				vo.setPk_firstupdetail(pkFirstDetail);
				dao.update(vo);
				tempMakeDetailVoList.add(tempMakeDetailVo);

			}
		}


		makeVo.setChildrenVO(tempMakeDetailVoList.toArray(new BudgetMakeDetailVO[0]));
		if (spreplyDetailVos != null) {
			SpBudgetMakeDetailVO[] spmakeDetailVos = (SpBudgetMakeDetailVO[]) makeVo.getChildren(SpBudgetMakeDetailVO.class);
			Map<String, SpBudgetMakeDetailVO> spmakeDetailMap = new HashMap<String, SpBudgetMakeDetailVO>();
			for (SpBudgetMakeDetailVO vo : spmakeDetailVos) {
				spmakeDetailMap.put(vo.getDef1(), vo);
			}
			SpBudgetMakeDetailVO sptempMakeDetailVo = null;
			List<SpBudgetMakeDetailVO> sptempMakeDetailVoList = new ArrayList<SpBudgetMakeDetailVO>();
			for (SpBudgetReplyDetailVO vo : spreplyDetailVos) {

				sptempMakeDetailVo = spmakeDetailMap.get(vo.getDef1());

				BudgetReplyVO hvo = billVo.getParentVO();
				Integer taskstate = hvo.getTaskstate();
				if (sptempMakeDetailVo != null) { // 对应编制明细主键不为空
					sptempMakeDetailVo.setStatus(VOStatus.UPDATED);
					sptempMakeDetailVoList.add(sptempMakeDetailVo);
				} else {
					IdGenerator idGenerator = new SequenceGenerator();
					String pkFirstDetail = idGenerator.generate();
					sptempMakeDetailVo = new SpBudgetMakeDetailVO();
					sptempMakeDetailVo.setPk_spbudgetmakedetail(pkFirstDetail);
					sptempMakeDetailVo.setStatus(VOStatus.NEW);
					VOEntityUtil.copyVOByVO(sptempMakeDetailVo, SpBudgetReplyDetailVO.COPY_KEYS, vo,
							SpBudgetReplyDetailVO.COPY_KEYS);
					vo.setPk_firstupdetail(pkFirstDetail);
					dao.update(vo);
					sptempMakeDetailVoList.add(sptempMakeDetailVo);

				}
			}
			makeVo.setChildrenVO(sptempMakeDetailVoList.toArray(new SpBudgetMakeDetailVO[0]));
		}


		// 更新编制单据
		this.valAggBudgetMakeVO(makeVo);
	}

	public AggBudgetMakeVO findAggBudgetMakeVOByPk(String pk) throws BusinessException {
		return dao.findByPk(AggBudgetMakeVO.class, pk, false);
	}

	public void valAggBudgetMakeVO(AggBudgetMakeVO vo) throws BusinessException {

		// 验证子表不能为空
		ValidateChildLength.validateChildLength(vo);

		setDefaultVal(vo);

		// 计算子表vhashcode
		GetIdCode.getIdCode(vo.getAllChildrenVO());

		// 唯一性校验，年度+编制科室+表体行按编制预算维度唯一校验（支出预算+资本预算两种类型一起校验）。
		ValidateBudgetDetail validateBudgetDetail = new ValidateBudgetDetail();

		BudgetMakeDetailVO[] makechildArray = (BudgetMakeDetailVO[]) vo.getAllChildrenVO();
		ArrayList<BudgetMakeDetailVO> makechilds = new ArrayList<BudgetMakeDetailVO>(Arrays.asList(makechildArray));
		for (int i = makechilds.size() - 1; i >= 0; i--) {
			if (makechilds.get(i).getStatus() == 3) {
				makechilds.remove(i);
			}
		}
		BudgetMakeDetailVO[] makechildArrayInsert = makechilds
				.toArray(new BudgetMakeDetailVO[0]);
		vo.setChildrenVO(makechildArrayInsert);

		validateBudgetDetail.validateBudgetDetail(vo, BudgetMakeDetailVO.getDefaultTableName(),
				BudgetMakeDetailVO.PK_BUDGETMAKEDETAIL);
//		dao.update(vo);//修改的不对所以注释掉，会导致审批时报ts不一致错误
	}

	/**
	 * 保存前处理一些默认值
	 *
	 * @param vos
	 */
	private void setDefaultVal(AggBudgetMakeVO... vos) throws BusinessException {
		// 其他默认值处理
		// 生成预算号
		GenerateBudgetNo generateBudgetNo = new GenerateBudgetNo();
		generateBudgetNo.generateBudgetNo(vos);
		// 表头年度、编制科室、预算类型赋值给表体字段
		SetChildColumnValue.setChildColumnValue(vos, true);
	}

	public AggBudgetReplyVO[] saveAggBudgetReplyVOBySummary(AggBudgetReplyVO vo) throws BusinessException {

		if (vo.getParentVO().getIsummary() != null) {
			if (!vo.getParentVO().getIsummary().booleanValue()) {
				setDefaultVal(vo);
			} else {
				setDefaultValDept(vo);
			}
		} else {
			setDefaultVal(vo);
		}

		// 计算子表vhashcode
		GetIdCode.getIdCode(vo.getAllChildrenVO());

		AggBudgetReplyVO[] newvos = dao.update(vo);
		// 唯一性校验，年度+编制科室+表体行按编制预算维度唯一校验（支出预算+资本预算两种类型一起校验）。
		if (vo.getParentVO().getIsummary() != null) {
			if (!vo.getParentVO().getIsummary().booleanValue()) {// 合并批复单不做唯一性校验
				ValidateBudgetDetail validateBudgetDetail = new ValidateBudgetDetail();
				String tableName = "hrpbm_budgetreplydetail";
				validateBudgetDetail.validateBudgetDetail(vo, tableName, "pk_budgetreplydetail");
			}
		} else {
			ValidateBudgetDetail validateBudgetDetail = new ValidateBudgetDetail();
			String tableName = "hrpbm_budgetreplydetail";
			validateBudgetDetail.validateBudgetDetail(vo, tableName, "pk_budgetreplydetail");
		}

		return newvos; // 更新

	}

	/**
	 * 保存前处理编码规则
	 *
	 * @param vos
	 */
	private void setBillCode(AggBudgetReplyVO... vos) throws BusinessException {
		if (ArrayUtils.isNotEmpty(vos)) {
			for (AggBudgetReplyVO vo : vos) {
				String pk = getVOPrimaryKey(vo);
				if (StringUtils.isEmpty(pk)) {
					BillCodeContext billCodeContext = getBillCodeContext("hrpbmbudgetreply");
					String pk_group = InvocationInfoProxy.getInstance().getGroupId();
					if (billCodeContext != null && !billCodeContext.isPrecode()) {
						if (getMainVO(vo).getAttributeValue("billno") == null) {
							String code = getBillcodeManage().getBillCode_RequiresNew("hrpbmbudgetreply", pk_group,
									pk_group, getMainVO(vo));
							getMainVO(vo).setAttributeValue("billno", code);
						}
					} else {
						String code = (String) getMainVO(vo).getAttributeValue("billno");
						getBillcodeManage().commitPreBillCode("hrpbmbudgetreply", pk_group, pk_group, code);
					}
				}
			}
		}
	}

	/**
	 * 保存前设置审计信息
	 *
	 * @param vos
	 */
	private void setAuditInfo(AggBudgetReplyVO... vos) throws BusinessException {
		if (ArrayUtils.isNotEmpty(vos)) {
			UFDateTime now = new UFDateTime();
			for (AggBudgetReplyVO vo : vos) {
				String pk = getVOPrimaryKey(vo);
				if (StringUtils.isEmpty(pk)) {
					// 设置创建人创建时间
					getMainVO(vo).setAttributeValue("creator", InvocationInfoProxy.getInstance().getUserId());
					getMainVO(vo).setAttributeValue("creationtime", now);
					getMainVO(vo).setAttributeValue("billmaketime", now);
				} else {
					// 设置修改人修改时间
					getMainVO(vo).setAttributeValue("modifier", InvocationInfoProxy.getInstance().getUserId());
					getMainVO(vo).setAttributeValue("modifiedtime", now);
					getMainVO(vo).setAttributeValue("lastmaketime", now);
				}

				//HPCLOUD-36201  一下，二下预算批复单修改保存后，使用当前用户更新制人字段。 2024年6月28日
				if (Objects.nonNull(vo.getParentVO().getBillmaker())) {
					vo.getParentVO().setBillmaker(InvocationInfoProxy.getInstance().getUserId());
				}
			}
		}
	}

	/**
	 * 保存前生成预算号
	 *
	 * @throws BusinessException
	 */
	private void setBudgetNo(AggBudgetReplyVO... vos) throws BusinessException {
		if (ArrayUtils.isNotEmpty(vos)) {
			String maxFlowNo = "00000";
			BudgetNoVO budgetNoVO = new BudgetNoVO();
			// 获取当前vo中集团、业务单元预算科室和年度对应的最大流水号
			VOQuery<BudgetNoVO> noQuery = new VOQuery<>(BudgetNoVO.class);
			SqlBuffer noSqlBuffer = new SqlBuffer();
			noSqlBuffer.append(" and ");
			noSqlBuffer.append(BudgetNoVO.PK_GROUP, vos[0].getParentVO().getPk_group());
			noSqlBuffer.append(" and ");
			noSqlBuffer.append(BudgetNoVO.PK_ORG, vos[0].getParentVO().getPk_org());
			noSqlBuffer.append(" and ");
			noSqlBuffer.append(BudgetNoVO.NYEAR, vos[0].getParentVO().getNyear());
			noSqlBuffer.append(" and ");
			noSqlBuffer.append(BudgetNoVO.PK_DEPT, vos[0].getParentVO().getPk_budgetdept());
			BudgetNoVO[] budgetNoVOs = noQuery.query(noSqlBuffer.toString(), null);
			IBudgetNoVOService budgetNoVOService = NCLocator.getInstance().lookup(IBudgetNoVOService.class);
			if (budgetNoVOs.length > 0) {
				budgetNoVO = budgetNoVOService.findBudgetNoVOByPk(budgetNoVOs[0].getPk_budgetno(), false);
				maxFlowNo = budgetNoVO.getFlowno();
				budgetNoVO.setStatus(VOStatus.UPDATED);
			} else {// 如果没有记录则插入一条，设置flowno为0
				budgetNoVO = new BudgetNoVO();
				budgetNoVO.setPk_group(vos[0].getParentVO().getPk_group());
				budgetNoVO.setPk_org(vos[0].getParentVO().getPk_org());
				budgetNoVO.setNyear(vos[0].getParentVO().getNyear());
				budgetNoVO.setPk_dept(vos[0].getParentVO().getPk_budgetdept());
				VOQuery<BudgetDeptVO> bQuery = new VOQuery<>(BudgetDeptVO.class);
				BudgetDeptVO[] budgetDeptVOs = bQuery.query(new String[]{vos[0].getParentVO().getPk_budgetdept()});
				if (budgetDeptVOs.length <= 0) {
					throw new BusinessException("生成预算号时，没有查找到编制科室信息，请排查");
				}
				budgetNoVO.setDeptcode(budgetDeptVOs[0].getCode());
				budgetNoVO.setFlowno(maxFlowNo);
				budgetNoVO.setStatus(VOStatus.NEW);
			}
			// 子表中预算号为空的，生成预算号并填入
			BudgetReplyDetailVO[] budgetReplyDetailVOs = (BudgetReplyDetailVO[]) vos[0].getChildren(BudgetReplyDetailVO.class);
			if (Objects.nonNull(budgetReplyDetailVOs)) {
				for (int i = 0; i < budgetReplyDetailVOs.length; i++) {
					BudgetReplyDetailVO budgetReplyDetailVO = budgetReplyDetailVOs[i];
					if (Objects.isNull(budgetReplyDetailVO.getBudgetno())) {
						Integer nextFlowNo = Integer.parseInt(maxFlowNo) + i + 1;
						maxFlowNo = String.format("%05d", nextFlowNo);
						budgetReplyDetailVO.setBudgetno(budgetNoVO.getDeptcode() + budgetNoVO.getNyear() + maxFlowNo);
					}
				}
			}
			// 更新预算科室和对应年度的最大流水号
			budgetNoVO.setFlowno(maxFlowNo);
			budgetNoVOService.saveBudgetNoVO(budgetNoVO);
		}
	}

	/**
	 * 根据编制单的交易类型，确定批复单的交易类型
	 *
	 * @throws BusinessException
	 */
	private void initTransTypeData(BudgetReplyVO vo) throws BusinessException {
		String makeTransTypeCode = vo.getTranstype();
		makeTransTypeCode = makeTransTypeCode.substring(makeTransTypeCode.indexOf("-"));
		makeTransTypeCode = vo.getBilltype() + makeTransTypeCode;
		vo.setTranstype(makeTransTypeCode);
		BilltypeVO billtypeVO = BillTypeQueryTools.queryBillTypeById(makeTransTypeCode);
		if (Objects.isNull(billtypeVO)) {
			throw new BusinessException("没有对应的交易类型:" + makeTransTypeCode);
		}
		vo.setTranstypepk(billtypeVO.getPk_billtypeid());
	}

	/**
	 * 保存前处理一些默认值
	 *
	 * @param vos
	 */
	private void setDefaultVal(AggBudgetReplyVO... vos) throws BusinessException {
		setBillCode(vos);
		setAuditInfo(vos);
		// 其他默认值处理 modify by wy at 2027适配930
		// setBudgetNo(vos);
		// 设置默认值
		for (AggBudgetReplyVO vo : vos) {
			getMainVO(vo).setStatus(VOStatus.NEW);
			initDefaultData(vo.getParentVO());
			initTransTypeData(vo.getParentVO());
		}
		SetChildColumnValue.setChildColumnValue(vos, true);
	}

	/**
	 * 保存前处理一些默认值
	 *
	 * @param vos
	 */
	private void setDefaultValDept(AggBudgetReplyVO... vos) throws BusinessException {
		setBillCode(vos);
		setAuditInfo(vos);
		// 其他默认值处理 modify by wy at 2027适配930
		// setBudgetNo(vos);
		// 设置默认值
		for (AggBudgetReplyVO vo : vos) {
			getMainVO(vo).setStatus(VOStatus.NEW);
			initDefaultData(vo.getParentVO());
			initTransTypeData(vo.getParentVO());
		}
		SetChildColumnValue.setChildColumnValue(vos, false);
	}

	// 给单表（行编辑表）单独适配
	@Override
	public AggBudgetReplyVO[] saveAggBudgetReplyVO(AggBudgetReplyVO[] vos) throws BusinessException {
		setDefaultVal(vos);
		return dao.save(vos, true);
	}

	@Override
	public AggBudgetReplyVO[] deleteAggBudgetReplyVOs(Map<String, String> tsMap) throws BusinessException {
		AggBudgetReplyVO[] vos = dao.listByPk(AggBudgetReplyVO.class, tsMap.keySet().toArray(new String[0]));
		validate(vos, tsMap);
		String pk_group = InvocationInfoProxy.getInstance().getGroupId();
		Arrays.stream(vos).forEach(vo -> {
			String code = (String) getMainVO(vo).getAttributeValue("billno");
			try {
				getBillcodeManage().returnBillCodeOnDelete("hrpbmbudgetreply", pk_group, pk_group, code, vo);
			} catch (BusinessException e) {
				e.printStackTrace();
			}
		});
		dao.delete(vos, true);
		//ADD BY WW 2024-04-010 删除批复单时 删除临时预算
		BmBudgetControlServiceImpl controlService = new BmBudgetControlServiceImpl();
		controlService.deleteTempBudget(vos);
		return vos;
	}

	// 校验 包括ts校验
	private void validate(AggBudgetReplyVO[] vos, Map<String, String> tsMap) throws BusinessException {

		Boolean isPass = true;
		if (ArrayUtils.isEmpty(vos)) {
			isPass = false;
		}
		for (AggBudgetReplyVO vo : vos) {

			SuperVO mainvo = vo.getParentVO();
			UFDateTime ts = (UFDateTime) mainvo.getAttributeValue("ts");
			if (!StringUtils.equals(tsMap.get(mainvo.getPrimaryKey()), ts.toString())) {
				isPass = false;
				break;
			}
		}
		if (!isPass) {
			throw new BusinessException("您操作的数据已被他人修改或删除，请刷新后重试！");
		}
	}

	@Override
	public <T> T[] loadTreeData(Class<T> clazz, Map<String, Object> userJson) throws BusinessException {
		return dao.listByCondition(clazz, " dr = 0 ", false);
	}

	@Override
	public String[] queryChildPksByParentId(Class childClazz, String parentId) throws BusinessException {
		String cond = " pk_budgetreply = '" + parentId + "' ";
		SuperVO[] vos = (SuperVO[]) dao.listByCondition(childClazz, cond, false);
		if (vos == null || vos.length == 0) {
			return new String[0];
		}
		return Stream.of(vos).map(vo -> vo.getPrimaryKey()).toArray(String[]::new);
	}

	public SuperVO[] queryChildVOByPks(Class childClazz, String[] pks) throws BusinessException {
		return (SuperVO[]) dao.listByPk(childClazz, pks, false);
	}

	/**
	 * 提交前校验: 检查单据状态
	 *
	 * @throws BusinessException
	 */
	private void validateCommitAggBudgetReplyVO(AggBudgetReplyVO... vos) throws BusinessException {
		if (ArrayUtils.isEmpty(vos)) {
			return;
		}
		List<AggBudgetReplyVO> list = Arrays.stream(vos).filter(item -> item.getParentVO() != null).filter(item -> {
			Integer status = (Integer) item.getParentVO().getAttributeValue("approvestatus");
			return status == null
					|| status != BillStatusEnum.FREE.toIntValue() && status != BillStatusEnum.NOPASS.toIntValue();
		}).map(item -> item).collect(Collectors.toList());
		if (list == null || list.size() == 0) {
			return;
		}
		String errors = "";
		for (AggBudgetReplyVO vo : list) {
			errors += "单据号：[" + vo.getParentVO().getAttributeValue("billno") + "]提交失败，失败原因：单据状态不正确，请检查。\n";
		}
		throw new BusinessException(errors);
	}

	/**
	 * 收回前校验: 检查单据状态
	 *
	 * @throws BusinessException
	 */
	private void validateUnCommitAggBudgetReplyVO(AggBudgetReplyVO... vos) throws BusinessException {
		if (ArrayUtils.isEmpty(vos)) {
			return;
		}
		List<AggBudgetReplyVO> list = Arrays.stream(vos).filter(item -> item.getParentVO() != null).filter(item -> {
			Integer status = (Integer) item.getParentVO().getAttributeValue("approvestatus");
			return status == null || status == BillStatusEnum.FREE.toIntValue();
		}).map(item -> item).collect(Collectors.toList());
		if (list == null || list.size() == 0) {
			return;
		}
		String errors = "";
		for (AggBudgetReplyVO vo : list) {
			errors += "单据号：[" + vo.getParentVO().getAttributeValue("billno") + "]提交失败，失败原因：单据状态不正确，请检查。\n";
		}
		throw new BusinessException(errors);
	}

	@Override
	public AggBudgetReplyVO commitAggBudgetReplyVO(String actionName, Map<String, String> tsMap)
			throws BusinessException {
		BillQuery<AggBudgetReplyVO> query = new BillQuery<AggBudgetReplyVO>(AggBudgetReplyVO.class);
		AggBudgetReplyVO[] vos =  query.query(getAllPks(tsMap));
//		AggBudgetReplyVO[] vos = dao.listByPk(AggBudgetReplyVO.class, getAllPks(tsMap), true);
		validateTs(tsMap, vos);
		// 提交前校验及业务逻辑
		validateCommitAggBudgetReplyVO(vos);
		Map<String, Object> res = this.execFlows(actionName, "BM25", vos);
		// 提交后业务逻辑
		return vos[0];
	}

	@Override
	public void batchCommitAggBudgetReplyVO(String actionName, Map<String, String> tsMap) throws BusinessException {
		AggBudgetReplyVO[] vos = dao.listByPk(AggBudgetReplyVO.class, getAllPks(tsMap), true);
		validateTs(tsMap, vos);
		// 批量提交前校验及业务逻辑
		validateCommitAggBudgetReplyVO(vos);
		Map<String, Object> res = this.execFlows(actionName, "BM25", vos);
		// 批量提交后业务逻辑
	}

	@Override
	public AggBudgetReplyVO uncommitAggBudgetReplyVO(String actionName, Map<String, String> tsMap)
			throws BusinessException {
		AggBudgetReplyVO[] vos = dao.listByPk(AggBudgetReplyVO.class, getAllPks(tsMap), true);
		validateTs(tsMap, vos);
		// 收回前校验及业务逻辑
		validateUnCommitAggBudgetReplyVO(vos);
		Map<String, Object> res = this.execFlows(actionName, "BM25", vos);
		// 收回后业务逻辑
		return vos[0];
	}

	@Override
	public void batchUncommitAggBudgetReplyVO(String actionName, Map<String, String> tsMap) throws BusinessException {
		AggBudgetReplyVO[] vos = dao.listByPk(AggBudgetReplyVO.class, getAllPks(tsMap), true);
		validateTs(tsMap, vos);
		// 批量收回前校验及业务逻辑
		validateUnCommitAggBudgetReplyVO(vos);
		Map<String, Object> res = this.execFlows(actionName, "BM25", vos);
		// 批量收回后业务逻辑
	}

	@Override
	public AggBudgetReplyVO[] callbackSAVEBASE(AggBudgetReplyVO... vos) throws BusinessException {
		if (ArrayUtils.isEmpty(vos)) {
			return null;
		}
		// 同步单据状态和审批状态(只有提交时候需要手动设置审批状态。其余审批完后审批状态都已更新)
		List<AggBudgetReplyVO> update = new ArrayList<>(), insert = new ArrayList<>();
		Arrays.stream(vos).forEach(item -> {
			if (StringUtils.isEmpty(item.getPrimaryKey())) {
				insert.add(item);
			} else {
				update.add(item);
			}
		});
		List<AggBudgetReplyVO> ret = new ArrayList<>();
		if (insert.size() > 0) {
			ret.addAll(Arrays.asList(dao.insert(insert.toArray(new AggBudgetReplyVO[0]))));
		}
		if (update.size() > 0) {
			ret.addAll(Arrays.asList(dao.update(update.toArray(new AggBudgetReplyVO[0]))));
		}
		return ret.toArray(new AggBudgetReplyVO[0]);

	}

	@Override
	public AggBudgetReplyVO[] callbackSAVE(AggBudgetReplyVO... vos) throws BusinessException {
		if (ArrayUtils.isEmpty(vos)) {
			return null;
		}
		// 同步单据状态和审批状态(只有提交时候需要手动设置审批状态。其余审批完后审批状态都已更新)
		Arrays.stream(vos).forEach(v -> {
			// modify by wy at 适配930 2024年10月28日
//			v.getParent().setAttributeValue("approvestatus", nc.ui.pubapp.uif2app.actions.pflow.ApproveStatus.COMMIT);
			v.getParent().setAttributeValue("approvestatus", BillStatusEnum.COMMIT.toIntValue());
		});
		List<AggBudgetReplyVO> update = new ArrayList<>(), insert = new ArrayList<>();

		for (AggBudgetReplyVO item : vos) {
			if (item.getParentVO().getApprovestatus().equals(ApproveStateEnum.COMMIT)) {
				item = (AggBudgetReplyVO) taskStateManager.taskStateProcess(item, TaskStateProcessAction.COMMIT, false,
						false);
			}
			if (StringUtils.isEmpty(item.getPrimaryKey())) {
				insert.add(item);
			} else {
				update.add(item);
			}
		}

		List<AggBudgetReplyVO> ret = new ArrayList<>();
		if (insert.size() > 0) {
			ret.addAll(Arrays.asList(dao.insert(insert.toArray(new AggBudgetReplyVO[0]))));
		}
		if (update.size() > 0) {
			ret.addAll(Arrays.asList(dao.update(update.toArray(new AggBudgetReplyVO[0]))));
		}
		return ret.toArray(new AggBudgetReplyVO[0]);

	}

	@Override
	public AggBudgetReplyVO[] callbackUNSAVE(AggBudgetReplyVO... vos) throws BusinessException {
		if (ArrayUtils.isEmpty(vos)) {
			return null;
		}

		String makeUpPk = "";
		IBudgetMakeVOService budgetMakeVOService = NCLocator.getInstance().lookup(IBudgetMakeVOService.class);
		IBudgetAdjustVOService budgetAdjustVOService = NCLocator.getInstance().lookup(IBudgetAdjustVOService.class);
		for (AggBudgetReplyVO item : vos) {
			if (item.getParentVO().getTaskprocess() == 1) { // 一上一下单据，判断编制单是否已经调整，调整的不允许收回
				makeUpPk = item.getParentVO().getPk_firstupbill();
				// 判断是否生成调整单
				AggBudgetAdjustVO[] adjustvos = budgetAdjustVOService
						.listAggBudgetAdjustVOByCondition("pk_budgetmake = '" + makeUpPk + "'");
				if (adjustvos.length > 0) {
					throw new BusinessException("批复单对应一上编制单已生成调整单，不允许收回！");
				}
			} else {// 二上二下单据
				// 如果任务阶段时
				if (item.getParentVO().getTaskstage() <= 2) {// 一上一下阶段,判断二上编制单状态，二上编制二上处理时可以收回
					AggBudgetMakeVO[] makevo = budgetMakeVOService
							.listAggBudgetMakeVOByCondition("PK_FIRSTDOWNBILL ='" + item.getPrimaryKey() + "'");
					if (makevo.length > 0) {
						// modify by wy at 适配930 2024年10月29日
						String condition = " pk_summarybill = '" + makevo[0].getParentVO().getPk_budgetmake() + "' and HASSUMMARY = 'Y'";
						BudgetMakeVO[] summarybills = budgetMakeVOService.listBudgetMakeVOByCondition(condition);
						if (Objects.nonNull(summarybills) && summarybills.length > 0) {
							//if (makevo[0].getParentVO().getSummarybills() != null) {
							throw new BusinessException("此批复单生成的二上编制单状态为“已汇总”，不能收回或取消审批。");
						}
						if (makevo[0].getParentVO().getTaskstate() > TaskStateEnum.SecondUpProcess.toIntValue()) {
							throw new BusinessException("批复单对应二上编制单任务状态只有是二上上报或二上处理时，允许收回！");
						}
					}

				} else {// 二上二下阶段,判断二上编制单是否已经调整，调整的不允许收回
					makeUpPk = item.getParentVO().getPk_secondupbill();
					// 判断是否生成调整单
					AggBudgetAdjustVO[] adjustvos = budgetAdjustVOService
							.listAggBudgetAdjustVOByCondition("pk_budgetmake = '" + makeUpPk + "'");
					if (adjustvos.length > 0) {
						throw new BusinessException("批复单对应二上编制单已生成调整单，不允许收回！");
					}
				}
			}
		}

		// 同步单据状态和审批状态(只有提交时候需要手动设置审批状态。其余审批完后审批状态都已更新)
		List<AggBudgetReplyVO> update = new ArrayList<>(), insert = new ArrayList<>();
		for (AggBudgetReplyVO item : vos) {
			item = (AggBudgetReplyVO) taskStateManager.taskStateProcess(vos[0], TaskStateProcessAction.CALLBACK, false,
					true);
			if (StringUtils.isEmpty(item.getPrimaryKey())) {
				insert.add(item);
			} else {
				update.add(item);
			}
		}
		List<AggBudgetReplyVO> ret = new ArrayList<>();
		if (insert.size() > 0) {
			ret.addAll(Arrays.asList(dao.insert(insert.toArray(new AggBudgetReplyVO[0]))));
		}
		if (update.size() > 0) {
			ret.addAll(Arrays.asList(dao.update(update.toArray(new AggBudgetReplyVO[0]))));
		}
		AggBudgetReplyVO[] aggvos = ret.toArray(new AggBudgetReplyVO[0]);
		CGFourWriteBakDataUtil.callbackUNSAVEAggBudgetReplyVO(aggvos);
		return ret.toArray(new AggBudgetReplyVO[0]);

	}

	@Override
	public AggBudgetReplyVO[] callbackAPPROVE(AggBudgetReplyVO... vos) throws BusinessException {
		if (ArrayUtils.isEmpty(vos)) {
			return null;
		}

		// 同步单据状态和审批状态(只有提交时候需要手动设置审批状态。其余审批完后审批状态都已更新)
		List<AggBudgetReplyVO> update = new ArrayList<>(), insert = new ArrayList<>();
		for (AggBudgetReplyVO item : vos) {
			// TO WW 要查还不全查出来，本来3行代码搞定，非要写4行！
			BudgetReplyVO headvo = item.getParentVO();
			item = this.findAggBudgetReplyVOByPk(item.getPrimaryKey());
			item.setParent(headvo);

//			// ADD BY WW 有时候聚合VO的表体数据为空，准确的说是表体数组的第一个对象值为null，需要重新查询
//			BudgetReplyDetailVO[] replyDetails = (BudgetReplyDetailVO[]) dao.listByCondition(BudgetReplyDetailVO.class,
//					" dr = 0 and pk_budgetreply = '" + item.getPrimaryKey() + "'");
//			if (replyDetails != null)
//				item.setChildren(BudgetReplyDetailVO.class, replyDetails);

//			if (item.getParentVO().getApprovestatus().equals(ApproveStatus.FREE)) {
			// modify by wy at 适配930 2024年10月28日
			if (item.getParentVO().getApprovestatus().equals(BillStatusEnum.FREE.toIntValue())) {
				item = (AggBudgetReplyVO) taskStateManager.taskStateProcess(item, TaskStateProcessAction.CALLBACK,
						false, false);
//			} else if (item.getParentVO().getApprovestatus().equals(ApproveStatus.APPROVING)) {

				// modify by wy at 适配930 2024年10月28日
			} else if (item.getParentVO().getApprovestatus().equals(BillStatusEnum.APPROVING.toIntValue())) {

//			} else if (item.getParentVO().getApprovestatus().equals(ApproveStatus.APPROVED)) {

				// modify by wy at 适配930 2024年10月28日
			} else if (item.getParentVO().getApprovestatus().equals(BillStatusEnum.APPROVED.toIntValue())) {
				if (item.getParentVO().getIsummary() == null) {
					item = (AggBudgetReplyVO) taskStateManager.taskStateProcess(item, TaskStateProcessAction.APPROVE,
							false, true);
				} else {
					if (!item.getParentVO().getIsummary().booleanValue()) { // 非合并批复单据
						item = (AggBudgetReplyVO) taskStateManager.taskStateProcess(item,
								TaskStateProcessAction.APPROVE, false, true);
					} else {// 合并批复单据修改单据任务状态 为一下批复或二下批复
						if (item.getParentVO().getTaskstage() == 2) {
							item.getParentVO().setTaskstate(TaskStateEnum.FirstDownReply.toIntValue());
						} else {
							item.getParentVO().setTaskstate(TaskStateEnum.SecondDownReply.toIntValue());
						}
					}
				}

			}
			if (StringUtils.isEmpty(item.getPrimaryKey())) {
				insert.add(item);
			} else {
				update.add(item);
			}

			if (item.getParentVO().getIsummary() != null) {

				// 当是合并批复需要做特殊处理
				if (item.getParentVO().getIsummary().booleanValue()) {
					// 1.获取对应汇总上报的预算编制单pk
					String pkmake = "";
					if (item.getParentVO().getTaskstage() <= 2) {// 一上一下
						pkmake = item.getParentVO().getPk_firstupbill();
					} else {
						pkmake = item.getParentVO().getPk_secondupbill();
					}
					// 2.根据编制单pk查询科室上报归口，再根据归口编制单查询出对应的批复单
					StringBuilder deptMakePkWhere = new StringBuilder();
					AggBudgetMakeVO[] deptMakeAggvos = dao.listByCondition(AggBudgetMakeVO.class,
							" PK_SUMMARYBILL = '" + pkmake + "' and dr = 0 ");
					for (AggBudgetMakeVO deptMakeAggvo : deptMakeAggvos) {
						deptMakePkWhere.append("'" + deptMakeAggvo.getParentVO().getPk_budgetmake() + "',");
					}
					String sqlWhere = deptMakePkWhere.toString();
					String sq = sqlWhere.substring(0, sqlWhere.length() - 1);
					AggBudgetReplyVO[] deptreplyAggvos = dao.listByCondition(
							AggBudgetReplyVO.class,
							"(PK_FIRSTUPBILL in (" + sq + ") or PK_SECONDUPBILL in (" + sq + ")) and dr = 0 ");
					BudgetReplyDetailVO[] replySumDetails = (BudgetReplyDetailVO[]) item.getChildren(BudgetReplyDetailVO.class);
					// 3.根据汇总科室批复单，修改科室批复单的审批信息及预算数
					for (AggBudgetReplyVO deptReplyAggVo : deptreplyAggvos) {
						List<BudgetReplyDetailVO> matchDetailVos = new ArrayList<BudgetReplyDetailVO>();
						// 根据编制科室来获取汇总批复子表行中的对应的科室批复单
						String deptPk = deptReplyAggVo.getParentVO().getPk_budgetdept();
						// 遍历汇总批复单子表
						for (BudgetReplyDetailVO replySumDetail : replySumDetails) {
							if (deptPk.equals(replySumDetail.getPk_budgetdept())) {
								matchDetailVos.add(replySumDetail); // 获取到该科室批复单在汇总批复单里处理的数据
							}
						}
						BudgetReplyDetailVO[] replyDeptDetails = (BudgetReplyDetailVO[]) deptReplyAggVo
								.getChildren(BudgetReplyDetailVO.class);

						List<BudgetReplyDetailVO> detailvos = new ArrayList<BudgetReplyDetailVO>(
								Arrays.asList(replyDeptDetails));
						// 根据汇总的数据进行科室批复单数据回写
						for (BudgetReplyDetailVO matchDetailVo : matchDetailVos) {
							String pkdetail = null;
							if (item.getParentVO().getTaskstage() <= 2) {// 一上一下
								if (matchDetailVo.getAmount_firstup() != null) {// 修改行
									pkdetail = matchDetailVo.getPk_firstdowndetail();
								}
							} else {
								if (matchDetailVo.getAmount_secondup() != null) {// 修改行
									pkdetail = matchDetailVo.getPk_seconddowndetail();
								}
							}
							// 回写值
							if (pkdetail != null) {
								for (BudgetReplyDetailVO deptDetail : replyDeptDetails) {
									if (pkdetail.equals(deptDetail.getPk_budgetreplydetail())) {// 回写数据到原科室批复子表行
										deptDetail.setStatus(1);
										deptDetail.setAmount_firstdown(matchDetailVo.getAmount_firstdown());
										deptDetail.setAmount_seconddown(matchDetailVo.getAmount_seconddown());
										// modify by wy at 2024年5月29日 增加字段回写 matchDetailVo:预算编制、deptDetail:预算批复
										List<Map<String, Object>> lists = DefdocUtils.getDefdoc("YSBZ_YSPF_COPM_0001");
										if (lists != null) {
											for (Map<String, Object> map : lists) {
												String ysbz = map.get("code").toString();
												String yspf = map.get("mnecode").toString();
												String attributeValue = deptDetail.getAttributeValue(yspf) == null ? ""
														: deptDetail.getAttributeValue(yspf).toString();
												deptDetail.setAttributeValue(ysbz, attributeValue);
												matchDetailVo.setAttributeValue(ysbz, attributeValue);

											}
										}
										// modify by wy at 2024年5月30日
									}
								}
							} else {// 新增行处理
								BudgetReplyDetailVO detailVo = new BudgetReplyDetailVO();
								// 设置status为插入2
								detailVo.setStatus(2);
								detailVo.setPk_project(matchDetailVo.getPk_project());
								detailVo.setPk_inoutclass(matchDetailVo.getPk_inoutclass());
								detailVo.setPk_fundsource(matchDetailVo.getPk_fundsource());
								detailVo.setPk_budgetreply(deptReplyAggVo.getPrimaryKey());
								detailVo.setBudgetno(matchDetailVo.getBudgetno());
								for (int i = 1; i < 11; i++) {
									detailVo.setAttributeValue("defdim" + i, matchDetailVo.getAttributeValue("defdim" + i));
								}
								detailVo.setAmount_firstdown(matchDetailVo.getAmount_firstdown());
								detailVo.setAmount_seconddown(matchDetailVo.getAmount_seconddown());
								detailVo.setFirstdown_memo(matchDetailVo.getFirstdown_memo());
								detailVo.setSeconddown_memo(matchDetailVo.getSeconddown_memo());
								detailvos.add(detailVo);
							}
							// modify by wy at 适配930 2024年10月29日
							// deptReplyAggVo.setChildrenVO(detailvos.toArray(new BudgetReplyDetailVO[0]));
						}

						deptReplyAggVo.setChildrenVO(detailvos.toArray(new BudgetReplyDetailVO[0]));
						// 4.修改批复单的审批状态，并更新
						deptReplyAggVo.getParentVO().setApprovestatus(1);// 审批状态，审批通过

						// 5.调用科室批复单的状态机执行后续操作
						if (item.getParentVO().getTaskstage() <= 2) {
							// 当二上二下流程合并批复会出现是对应的一下批复单已经批复并生成二上编制单完成的情况，
							// 此时调用状态机生成二上编制单会出现维度重复的错误，这种情况不执行状态机
							String valSecondMakeBill = "select count(*)  from hrpbm_budgetmake "
									+ "where pk_firstupbill = '" + deptReplyAggVo.getParentVO().getPk_firstupbill()
									+ "' and taskstage ='3'";
							Integer approvestatus = (Integer) getBaseDAO().executeQuery(valSecondMakeBill,
									new ColumnProcessor());
							if (approvestatus == 0) {
								deptReplyAggVo.getParentVO().setTaskstate(TaskStateEnum.FirstDownApprove.toIntValue());
								// 为什么执行两次saveAggBudgetReplyVOBySummary 首先saveAggBudgetReplyVOBySummary 方式是更新得方法
								// 1.第一遍为了将 批复数保存至数据库 否则taskStateManager.taskStateProcess 拿不到最新的批复数
								// 会出现批复数为空或批复数是旧值
								// 2.第二遍为了更新批复单状态，为了不修改状态机在此特殊处理
								this.saveAggBudgetReplyVOBySummary(deptReplyAggVo);
								deptReplyAggVo = (AggBudgetReplyVO) taskStateManager.taskStateProcess(deptReplyAggVo,
										TaskStateProcessAction.APPROVE, false, true);
								this.saveAggBudgetReplyVOBySummary(deptReplyAggVo);
							}
						} else {
							deptReplyAggVo.getParentVO().setTaskstate(TaskStateEnum.SecondDownApprove.toIntValue());
							this.saveAggBudgetReplyVOBySummary(deptReplyAggVo);
							deptReplyAggVo = (AggBudgetReplyVO) taskStateManager.taskStateProcess(deptReplyAggVo,
									TaskStateProcessAction.APPROVE, false, true);
							this.saveAggBudgetReplyVOBySummary(deptReplyAggVo);
						}
					}
				}
			}

		}

		List<AggBudgetReplyVO> ret = new ArrayList<>();
		if (insert.size() > 0) {
			ret.addAll(Arrays.asList(dao.insert(insert.toArray(new AggBudgetReplyVO[0]))));
		}
		if (update.size() > 0) {
			ret.addAll(Arrays.asList(dao.update(update.toArray(new AggBudgetReplyVO[0]))));
		}
		AggBudgetReplyVO[] arrvos = ret.toArray(new AggBudgetReplyVO[0]);
		// 预算批复审批通过回写 moddify by wy at 2024年11月18日
		CGFourWriteBakDataUtil.callbackAPPROVEAggBudgetReplyVO(arrvos);
		return ret.toArray(new AggBudgetReplyVO[0]);

	}

	@Override
	public AggBudgetReplyVO[] callbackUNAPPROVE(AggBudgetReplyVO... vos) throws BusinessException {
		if (ArrayUtils.isEmpty(vos)) {
			return null;
		}
		for (AggBudgetReplyVO item : vos) {
			if (item.getParentVO().getIsummary().booleanValue()) {
				throw new BusinessException("合并批复单已经审批通过，不允许取消审批！");
			}
		}

		String makeUpPk = "";
		IBudgetMakeVOService budgetMakeVOService = NCLocator.getInstance().lookup(IBudgetMakeVOService.class);
		IBudgetAdjustVOService budgetAdjustVOService = NCLocator.getInstance().lookup(IBudgetAdjustVOService.class);
		for (AggBudgetReplyVO item : vos) {
			if (item.getParentVO().getTaskprocess() == 1) { // 一上一下单据，判断编制单是否已经调整，调整的不允许收回
				makeUpPk = item.getParentVO().getPk_firstupbill();
				AggBudgetMakeVO makevo = budgetMakeVOService.findAggBudgetMakeVOByPk(makeUpPk);
				// 判断是否生成调整单
				AggBudgetAdjustVO[] adjustvos = budgetAdjustVOService
						.listAggBudgetAdjustVOByCondition("pk_budgetmake = '" + makeUpPk + "'");
				if (adjustvos.length > 0) {
					throw new BusinessException("批复单对应一上编制单已生成调整单，不允许收回！");
				}

			} else {// 二上二下单据
				// 如果任务阶段时
				if (item.getParentVO().getTaskstage() <= 2) {// 一上一下阶段,判断二上编制单状态，二上编制二上处理时可以收回
					AggBudgetMakeVO[] makevo = budgetMakeVOService
							.listAggBudgetMakeVOByCondition("PK_FIRSTDOWNBILL ='" + item.getPrimaryKey() + "'");
					// modify by wy at 适配930 2024年10月29日
					// if (makevo[0].getParentVO().getSummarybills() != null) {
					if (makevo.length > 0) {
						String condition = " pk_summarybill = '" + makevo[0].getParentVO().getPk_budgetmake() + "' and HASSUMMARY = 'Y'";
						BudgetMakeVO[] summarybills = budgetMakeVOService.listBudgetMakeVOByCondition(condition);
						if (Objects.nonNull(summarybills) && summarybills.length > 0) {
							throw new BusinessException("此批复单生成的二上编制单状态为“已汇总”，不能收回或取消审批。");
						}
						if (makevo[0].getParentVO().getTaskstate() > TaskStateEnum.SecondUpProcess.toIntValue()) {
							throw new BusinessException("批复单对应二上编制单任务状态只有是二上上报或二上处理时，允许收回！");
						}
					}
				} else {// 二上二下阶段,判断二上编制单是否已经调整，调整的不允许收回
					makeUpPk = item.getParentVO().getPk_secondupbill();
					AggBudgetMakeVO makevo = budgetMakeVOService.findAggBudgetMakeVOByPk(makeUpPk);
					// 判断是否生成调整单
					AggBudgetAdjustVO[] adjustvos = budgetAdjustVOService
							.listAggBudgetAdjustVOByCondition("pk_budgetmake = '" + makeUpPk + "'");
					if (adjustvos.length > 0) {
						throw new BusinessException("批复单对应二上编制单已生成调整单，不允许收回！");
					}
				}
			}
		}
		// 同步单据状态和审批状态(只有提交时候需要手动设置审批状态。其余审批完后审批状态都已更新)
		List<AggBudgetReplyVO> update = new ArrayList<>(), insert = new ArrayList<>();
		for (AggBudgetReplyVO item : vos) {
			item = (AggBudgetReplyVO) taskStateManager.taskStateProcess(item, TaskStateProcessAction.UNAPPROVE, false,
					true);
			if (StringUtils.isEmpty(item.getPrimaryKey())) {
				insert.add(item);
			} else {
				update.add(item);
			}
		}
		List<AggBudgetReplyVO> ret = new ArrayList<>();
		if (insert.size() > 0) {
			ret.addAll(Arrays.asList(dao.insert(insert.toArray(new AggBudgetReplyVO[0]))));
		}
		if (update.size() > 0) {
			ret.addAll(Arrays.asList(dao.update(update.toArray(new AggBudgetReplyVO[0]))));
		}
		AggBudgetReplyVO[] arrvos = ret.toArray(new AggBudgetReplyVO[0]);

		// 预算批复审批通过回写 moddify by wy at 2024年11月18日
		CGFourWriteBakDataUtil.callbackUNSAVEAggBudgetReplyVO(arrvos);
		return ret.toArray(new AggBudgetReplyVO[0]);

	}

	@Override
	public BillCodeContext getBillCodeContext (String coderuleid) throws BusinessException {
		return super.getBillCodeContext(coderuleid);
	}

	@Override
	public BillCodeContext getBillCodeContext (String coderuleid, String pkgroup, String pkorg)
			throws BusinessException {
		return super.getBillCodeContext(coderuleid, pkgroup, pkorg);
	}
	@Override
	public void savebaseReplyByMake (AggBudgetMakeVO vo) throws BusinessException {
		// cloneVo
		AggBudgetReplyVO aggreplyVO = new AggBudgetReplyVO();
		BudgetReplyVO replyVO = new BudgetReplyVO();
		VOEntityUtil.copyVOByVO(replyVO, BudgetReplyVO.COPY_KEYS, vo.getParentVO(), BudgetReplyVO.COPY_KEYS);
		this.setTaskage(replyVO, vo);
		IBudgetMakeVOService budgetMakeVOService = NCLocator.getInstance().lookup(IBudgetMakeVOService.class);
		AggBudgetMakeVO vo2 = budgetMakeVOService.findAggBudgetMakeVOByPk(vo.getParentVO().getPk_budgetmake());
		//明细表复制
		BudgetMakeDetailVO[] makeDetailVOs = (BudgetMakeDetailVO[]) vo2.getChildren(BudgetMakeDetailVO.class);
		BudgetReplyDetailVO[] replyDetailVOs = new BudgetReplyDetailVO[makeDetailVOs.length];
		for (int i = 0; i < replyDetailVOs.length; i++) {
			replyDetailVOs[i] = new BudgetReplyDetailVO();
		}
		VOEntityUtil.copyVOsByVOs(replyDetailVOs, BudgetReplyDetailVO.COPY_KEYS, makeDetailVOs,
				BudgetReplyDetailVO.COPY_KEYS);
		for (int i = 0; i < replyDetailVOs.length; i++) {
			replyDetailVOs[i].setStatus(VOStatus.NEW);
			if (replyVO.getTaskstate().equals(TaskStateEnum.FirstUpReport.value())) {
				replyDetailVOs[i].setPk_firstupdetail(makeDetailVOs[i].getPk_budgetmakedetail());
			} else if (replyVO.getTaskstate().equals(TaskStateEnum.SecondUpReport.value())) {
				replyDetailVOs[i].setPk_secondupdetail(makeDetailVOs[i].getPk_budgetmakedetail());
			}
		}
		//专项子表复制 yx
		SpBudgetMakeDetailVO[] spmakeDetailVOs = (SpBudgetMakeDetailVO[]) vo2.getChildren(SpBudgetMakeDetailVO.class);
		if (spmakeDetailVOs != null) {
			SpBudgetReplyDetailVO[] spreplyDetailVOs = new SpBudgetReplyDetailVO[spmakeDetailVOs.length];
			for (int i = 0; i < spreplyDetailVOs.length; i++) {
				spreplyDetailVOs[i] = new SpBudgetReplyDetailVO();
			}
			VOEntityUtil.copyVOsByVOs(spreplyDetailVOs, SpBudgetReplyDetailVO.COPY_KEYS, spmakeDetailVOs,
					SpBudgetReplyDetailVO.COPY_KEYS);
			for (int i = 0; i < spreplyDetailVOs.length; i++) {
				spreplyDetailVOs[i].setStatus(VOStatus.NEW);
				if (replyVO.getTaskstate().equals(TaskStateEnum.FirstUpReport.value())) {
					spreplyDetailVOs[i].setPk_firstupdetail(spmakeDetailVOs[i].getPk_spbudgetmakedetail());
				} else if (replyVO.getTaskstate().equals(TaskStateEnum.SecondUpReport.value())) {
					spreplyDetailVOs[i].setPk_secondupdetail(spmakeDetailVOs[i].getPk_spbudgetmakedetail());
				}
			}
			aggreplyVO.setChildren(SpBudgetReplyDetailVO.class, spreplyDetailVOs);
			//资产配置预算
			AssetAllocationVO[] assetAllocationVOS = (AssetAllocationVO[]) vo2.getChildren(AssetAllocationVO.class);
			if (Objects.nonNull(assetAllocationVOS) && assetAllocationVOS.length > 0) {
				AssetAllocationReplyVO[] assetAllocationReplyVOS = new AssetAllocationReplyVO[assetAllocationVOS.length];
				for (int i = 0; i < assetAllocationReplyVOS.length; i++) {
					assetAllocationReplyVOS[i] = new AssetAllocationReplyVO();
				}
				VOEntityUtil.copyVOsByVOs(assetAllocationReplyVOS, AssetAllocationReplyVO.COPY_KEYS, assetAllocationVOS,
						AssetAllocationReplyVO.COPY_KEYS);
				for (int i = 0; i < assetAllocationReplyVOS.length; i++) {
					assetAllocationReplyVOS[i].setStatus(VOStatus.NEW);
				}
				aggreplyVO.setChildren(AssetAllocationReplyVO.class, assetAllocationReplyVOS);
			}
		}

		//政府采购预算
		GovpurchVO[] govpurchVOS = (GovpurchVO[]) vo2.getChildren(GovpurchVO.class);
		if (Objects.nonNull(govpurchVOS) && govpurchVOS.length > 0) {
			GovpurchReplyVO[] govpurchReplyVOS = new GovpurchReplyVO[govpurchVOS.length];
			for (int i = 0; i < govpurchReplyVOS.length; i++) {
				govpurchReplyVOS[i] = new GovpurchReplyVO();
			}
			VOEntityUtil.copyVOsByVOs(govpurchReplyVOS, GovpurchReplyVO.COPY_KEYS, govpurchVOS,
					GovpurchReplyVO.COPY_KEYS);
			for (int i = 0; i < govpurchReplyVOS.length; i++) {
				govpurchReplyVOS[i].setStatus(VOStatus.NEW);
			}
			aggreplyVO.setChildren(GovpurchReplyVO.class, govpurchReplyVOS);
		}


		aggreplyVO.setParentVO(replyVO);
		aggreplyVO.setChildren(BudgetReplyDetailVO.class, replyDetailVOs);
		this.saveAggBudgetReplyVO(aggreplyVO);
	}
	/**
	 * 根据编制状态，设置编制阶段，以及需要关联的pk
	 */
	private void setTaskage (BudgetReplyVO replyVO, AggBudgetMakeVO vo){
		replyVO.setApprovedate(null);
		replyVO.setApprovenote(null);
		replyVO.setApprover(null);
		replyVO.setApprovestatus(ApproveStateEnum.NOSTATE);
		replyVO.setModifier(null);
		replyVO.setModifiedtime(null);
		replyVO.setLastmaketime(null);
		if (replyVO.getTaskstate().equals(TaskStateEnum.FirstUpReport.value())) {// 一上上报
			replyVO.setPk_firstupbill(vo.getParentVO().getPk_budgetmake());// 批复单据，设置关联一上编制单主键
			replyVO.setTaskstage(TaskStageEnum.FirstDown.toIntValue());// 单据流程是一下
		}
		if (replyVO.getTaskstate().equals(TaskStateEnum.SecondUpReport.value())) {// 二上上报
			replyVO.setPk_secondupbill(vo.getParentVO().getPk_budgetmake());// 批复单据，设置关联二上编制单主键
			replyVO.setTaskstage(TaskStageEnum.SecondDown.toIntValue());// 单据流程是二下
		}
	}
	@Override
	public AggBudgetIndicatorVO queryAggBudgetIndicatorVO (String pk_org, String nyear, String pk_budgettype,
														   String pk_budgetdept) throws BusinessException {
		if (Objects.nonNull(nyear) && Objects.nonNull(pk_budgettype)) {
			String condition = "(pk_org = '" + pk_org + "' and nyear = '" + nyear + "' and pk_budgettype = '"
					+ pk_budgettype + "' and APPROVESTATUS = " + ApproveStateEnum.PASSING + ")";
			IBudgetIndicatorVOService budgetIndicatorVOService = NCLocator.getInstance()
					.lookup(IBudgetIndicatorVOService.class);
			AggBudgetIndicatorVO[] aggBudgetIndicatorVOs = budgetIndicatorVOService
					.listAggBudgetIndicatorVOByCondition(condition);
			if (Objects.nonNull(aggBudgetIndicatorVOs)) {
				if (aggBudgetIndicatorVOs.length == 1) {
					BudgetIndicatorBVO[] bvos = (BudgetIndicatorBVO[]) aggBudgetIndicatorVOs[0].getAllChildrenVO();
					List<BudgetIndicatorBVO> listbvos = new ArrayList<>();
					for (BudgetIndicatorBVO bvo : bvos) {
						if (Objects.nonNull(pk_budgetdept)) {// pk_budgetdept为null则不过滤子表
							if (bvo.getPk_budgetdept().equals(pk_budgetdept)) {
								listbvos.add(bvo);
							}
						}
					}
					AggBudgetIndicatorVO newAgg = new AggBudgetIndicatorVO();
					newAgg.setParentVO(aggBudgetIndicatorVOs[0].getParentVO());
					newAgg.setChildrenVO(listbvos.toArray(new BudgetIndicatorBVO[0]));
					return newAgg;
				} else if (aggBudgetIndicatorVOs.length > 1) {
					IBudgettypeService budgettypeService = NCLocator.getInstance().lookup(IBudgettypeService.class);
					Budgettype budgettype = budgettypeService.findBudgettypeByPk(pk_budgettype, false);
					throw new BusinessException(nyear + "年度下，预算类型：" + budgettype.getName() + "，对应的支出指标下达单据数量不唯一，请检查！");
				}
			}
		}
		return null;
	}
	@Override
	public void gentempctrl (String[]pks) throws BusinessException {
		AggBudgetReplyVO[] replyVOS = this.listAggBudgetReplyVOByPk(pks);
		if (Objects.nonNull(replyVOS) && replyVOS.length > 0) {
			IBmBudgetControlService budgetControlService = NCLocator.getInstance().lookup(IBmBudgetControlService.class);
			budgetControlService.pushTempBudget(replyVOS);
		}
	}
	/**
	 * 修改保存时将 删除的预算明细行和修改过维度的预算明细行 从业务控制平台的临时预算中删除
	 * 2024-05-14：当前临时预算只推送预算明细页签的数据
	 * @param replyVo
	 * @param oriReplyVO
	 * @throws BusinessException
	 */
	private void pushTempBudgetToCtrlForUpdateSave (AggBudgetReplyVO replyVo, AggBudgetReplyVO oriReplyVO) throws
			BusinessException {

		if (oriReplyVO == null)
			return;

		/*
		 * 从修改前、后的VO中获取 修改过预算维度的预算明细和删除的预算明细
		 *  以idcode作为判断依据，不存在于修改后VO的行则为删除行
		 */
		List<BudgetReplyDetailVO> replyDetailVos_del = new ArrayList<BudgetReplyDetailVO>();
		BudgetReplyDetailVO[] replyDetailVos = (BudgetReplyDetailVO[]) replyVo.getChildren(BudgetReplyDetailVO.class);
		Map<String, SuperVO> replyDetailVosIdCodeMap = BmControlPubUtils.getVoMap(replyDetailVos, BudgetReplyDetailVO.IDCODE);

		BudgetReplyDetailVO[] oriReplyDetailVos = (BudgetReplyDetailVO[]) oriReplyVO.getChildren(BudgetReplyDetailVO.class);

		BudgetReplyDetailVO replyDetailVo_del = null;
		for (BudgetReplyDetailVO oriReplyDetailVo : oriReplyDetailVos) {

			if (!replyDetailVosIdCodeMap.containsKey(oriReplyDetailVo.getIdcode())) {

				//克隆VO，需要修改VO状态，业务控制平台会过滤 状态为 删除的数据
				replyDetailVo_del = (BudgetReplyDetailVO) oriReplyDetailVo.clone();
				replyDetailVo_del.setStatus(VOStatus.UPDATED);//只要不是删除就行了

				replyDetailVos_del.add(replyDetailVo_del);

			}

		}

		if (replyDetailVos_del.size() > 0) {

			AggBudgetReplyVO replyVo_del = new AggBudgetReplyVO();

			replyVo_del.setParent(replyVo.getParentVO());
			replyVo_del.setChildren(BudgetReplyDetailVO.class, replyDetailVos_del.toArray(new BudgetReplyDetailVO[0]));

			BmBudgetControlServiceImpl controlService = new BmBudgetControlServiceImpl();
			controlService.deleteTempBudget(new AggBudgetReplyVO[]{replyVo_del});

		}

	}
	private BaseDAO getBaseDAO () {
		if (this.baseDAO == null) {
			this.baseDAO = new BaseDAO();
		}
		return this.baseDAO;
	}
}